# 教学示例代码：从意图识别 → 查库 → Prompt → 调大模型 → 生成Word → 返回URL
# 说明：为便于教学，本示例集中写在一个文件里，函数化，不封装类

import os
import json
import time
import uuid
import jieba
from datetime import datetime

from django.conf import settings
from django.http import JsonResponse
from django.db.models import Q

from user.models import User as CustomUser, JobInfo, WorkExperience
from docx import Document  # python-docx==1.2.0
from docx.shared import Pt, Inches

# 与 qa/views.py 一致的 OpenAI 兼容调用（阿里百炼 DashScope）
from openai import OpenAI

# 1) 意图识别（关键词法 + jieba）
def detect_intent_is_generate_resume(question: str) -> bool:
    if not question:
        return False
    # 基本关键词（你可以持续扩充）
    jieba.load_userdict("boss_zhipin_dict.txt")
    keywords = ["生成简历", "写简历", "做简历", "导出简历", "简历模板", "帮我写份简历", "简历优化", "简历word", "简历docx"]
    # 用 jieba 分词（学生没学过：jieba 是中文分词库，用于把句子切分成词，方便做关键词匹配）
    words = list(jieba.cut(question))
    text = "".join(words)
    return any(kw in question or kw in text for kw in keywords)

# 2) 查数据库（按用户ID，把可用信息尽量查全）
def fetch_user_resume_data(userid: int) -> dict:
    data = {
        "basic": {},
        "work_experiences": []
    }
    user = CustomUser.objects.filter(id=userid).first()
    job_info = JobInfo.objects.filter(user_id=userid).first()

    # 基本信息：从 user / job_info 尽量取
    if user:
        data["basic"]["phone"] = user.phone or ""
        data["basic"]["username"] = user.username or ""
        data["basic"]["email"] = user.email or ""

    if job_info:
        data["basic"]["name"] = job_info.name or ""
        data["basic"]["sex"] = job_info.sex if job_info.sex in (1, 2) else None
        data["basic"]["birthdate"] = job_info.birthdate.strftime("%Y-%m-%d") if job_info.birthdate else ""
        data["basic"]["education"] = job_info.education if job_info.education else None
        data["basic"]["current_status"] = job_info.current_status if job_info.current_status else None
        data["basic"]["avatar"] = job_info.aveter or ""
        # 取工作经历
        exps = WorkExperience.objects.filter(job_info=job_info).order_by("-start_date")
        for exp in exps:
            data["work_experiences"].append({
                "company": exp.company or "",
                "position": exp.position or "",
                "start_date": exp.start_date.strftime("%Y-%m-%d") if exp.start_date else "",
                "end_date": exp.end_date.strftime("%Y-%m-%d") if exp.end_date else "",
                "is_current": bool(exp.is_current),
                "description": exp.description or "",
                "industry": exp.industry if exp.industry else None
            })

    return data

# 3) 构造提示词（告诉大模型：哪些是真实数据；哪些缺失需要“补充并丰富”）
def build_prompt_for_resume(user_data: dict, question: str) -> str:
    # 教学重点：把“已有信息”原样陈述；把“缺失项”明确告诉模型需要补充，且要丰富
    # 同时给出 JSON Schema，要求“只输出 JSON，不要解释”
    basic = user_data.get("basic", {})
    work_exps = user_data.get("work_experiences", [])

    missing_items = []
    if not basic.get("name"):
        missing_items.append("姓名")
    if basic.get("education") is None:
        missing_items.append("最高学历")
    if not work_exps:
        missing_items.append("工作经历")
    if not basic.get("email"):
        missing_items.append("邮箱")
    if not basic.get("phone"):
        missing_items.append("电话")
    if not basic.get("birthdate"):
        missing_items.append("出生日期")

    schema = {
        "basic": {
            "name": "字符串，姓名（若未知请合理补充并标注(推断)）",
            "title": "字符串，期望职位标题（根据问题和经历推断）",
            "phone": "字符串，若未知请补充示例并标注(待完善)",
            "email": "字符串，若未知请补充示例并标注(待完善)",
            "city": "字符串，工作城市（可推断或留空说明）",
            "education": "字符串，例如 本科/硕士/大专（若未知请合理补充并标注(推断)）",
            "years": "整数，工作年限（根据经历推断或估算）",
            "skills": ["字符串，技能关键词，尽量丰富、专业"],
            "summary": "字符串，个人简介（300-500字，尽量丰富）"
        },
        "work_experiences": [
            {
                "company": "字符串",
                "position": "字符串",
                "start_date": "YYYY-MM",
                "end_date": "YYYY-MM 或 至今",
                "highlights": ["字符串，具体项目/业绩/指标，尽量量化"]
            }
        ],
        "projects": [
            {
                "name": "字符串",
                "role": "字符串",
                "tech_stack": ["字符串"],
                "description": "字符串，详尽描述",
                "achievements": ["字符串，量化成果"]
            }
        ],
        "educations": [
            {
                "school": "字符串",
                "degree": "字符串",
                "major": "字符串",
                "start_date": "YYYY-MM",
                "end_date": "YYYY-MM"
            }
        ]
    }

    prompt = f"""
你是资深简历顾问。现在请根据“已知用户信息”和“用户问题”，产出“结构化的JSON简历”。

【用户问题】:
{question}

【已知用户信息】(JSON):
{json.dumps(user_data, ensure_ascii=False)}

【缺失/不足项】:
{", ".join(missing_items) if missing_items else "无明显缺失，但请依然尽可能丰富"}

【重要要求】:
1. 请优先使用“已知信息”，对缺失项进行“合理补充”，并用“(推断)”或“(待完善)”清晰标注。
2. 简历要“非常丰富”，尤其是 summary / skills / projects / work_experiences 的 highlights，要写满且尽量量化。
3. 只输出 JSON，不要解释或多余文本。

【JSON Schema 示例】(字段含义见注释，不需要输出注释):
{json.dumps(schema, ensure_ascii=False, indent=2)}
"""
    return prompt

# 4) 调用大模型，生成 JSON（要求“只返回JSON”）
def call_llm_and_get_json(prompt: str) -> dict:
    client = OpenAI(
        api_key=os.getenv("DASHSCOPE_API_KEY"),
        base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
    )
    completion = client.chat.completions.create(
        model="qwen-plus",
        messages=[
            {"role": "system", "content": "你是专业的简历顾问，严格按用户的JSON Schema输出JSON。"},
            {"role": "user", "content": prompt},
        ],
        # 若需要，可设置温度或其他参数
    )
    content = completion.choices[0].message.content
    # 尝试解析为 JSON
    try:
        return json.loads(content)
    except Exception:
        # 兜底：若包含```json ... ```，尝试提取
        try:
            start = content.find("{")
            end = content.rfind("}")
            if start != -1 and end != -1 and end > start:
                return json.loads(content[start:end+1])
        except Exception:
            pass
    # 解析失败则返回空结构，让后续逻辑有兜底
    return {"basic": {}, "work_experiences": [], "projects": [], "educations": []}

# 5) 用 python-docx 把 JSON 写入 Word（.docx）
def render_docx_from_json(json_resume: dict, userid: int) -> str:
    doc = Document()

    # 字体样式辅助函数
    def add_heading(text, level=1):
        p = doc.add_heading(level=level)
        run = p.add_run(text)
        run.font.size = Pt(16 if level == 1 else 13)
        return p

    def add_paragraph(text, size=11):
        p = doc.add_paragraph()
        run = p.add_run(text)
        run.font.size = Pt(size)
        return p

    basic = json_resume.get("basic", {})
    name = basic.get("name", "姓名(待完善)")
    title = basic.get("title", "职位(待完善)")
    phone = basic.get("phone", "")
    email = basic.get("email", "")
    city = basic.get("city", "")
    education = basic.get("education", "")
    years = basic.get("years", "")
    summary = basic.get("summary", "")
    skills = basic.get("skills", [])

    # 标题
    add_heading(f"{name} - {title}", level=1)
    add_paragraph(f"电话：{phone}    邮箱：{email}    城市：{city}    学历：{education}    年限：{years}年")

    # 个人简介
    add_heading("个人简介", level=2)
    add_paragraph(summary, size=11)

    # 技能清单
    if skills:
        add_heading("技能特长", level=2)
        add_paragraph("、".join(skills), size=11)

    # 工作经历
    work_exps = json_resume.get("work_experiences", [])
    if work_exps:
        add_heading("工作经历", level=2)
        for exp in work_exps:
            company = exp.get("company", "")
            position = exp.get("position", "")
            start_date = exp.get("start_date", "")
            end_date = exp.get("end_date", "")
            line = f"{company} | {position} | {start_date} - {end_date}"
            add_paragraph(line, size=11)
            for h in exp.get("highlights", [])[:6]:
                add_paragraph(f"• {h}", size=11)

    # 项目经历
    projects = json_resume.get("projects", [])
    if projects:
        add_heading("项目经历", level=2)
        for prj in projects:
            name = prj.get("name", "")
            role = prj.get("role", "")
            stack = "、".join(prj.get("tech_stack", []))
            add_paragraph(f"{name} | {role} | 技术栈：{stack}")
            add_paragraph(prj.get("description", ""))
            for a in prj.get("achievements", [])[:5]:
                add_paragraph(f"• {a}", size=11)

    # 教育经历
    educations = json_resume.get("educations", [])
    if educations:
        add_heading("教育经历", level=2)
        for edu in educations:
            school = edu.get("school", "")
            degree = edu.get("degree", "")
            major = edu.get("major", "")
            sdate = edu.get("start_date", "")
            edate = edu.get("end_date", "")
            add_paragraph(f"{school} | {degree} {major} | {sdate} - {edate}")

    # 保存到 MEDIA_ROOT/resumes/
    folder = os.path.join(settings.MEDIA_ROOT, "resumes")
    if not os.path.exists(folder):
        os.makedirs(folder, exist_ok=True)
    filename = f"resume_{userid}_{int(time.time())}.docx"
    full_path = os.path.join(folder, filename)
    doc.save(full_path)
    return f"{settings.DOMAIN}{settings.MEDIA_URL}resumes/{filename}"

# 6) “控制流程”的主函数（可在APIView中直接调用）
def generate_resume_pipeline(question: str, userid: int) -> dict:
    # Step 1：意图识别
    if not detect_intent_is_generate_resume(question):
        return {"code": 400, "message": "不是简历生成意图", "data": {"question": question}}

    # Step 2：查库
    user_data = fetch_user_resume_data(userid)

    # Step 3：构造 Prompt
    prompt = build_prompt_for_resume(user_data, question)

    # Step 4：调用大模型 → JSON
    json_resume = call_llm_and_get_json(prompt)

    # Step 5：生成 Word 简历
    docx_url = render_docx_from_json(json_resume, userid)

    # Step 6：返回
    return {
        "code": 200,
        "message": "SUCCESS",
        "data": {
            "question": question,
            "json_resume": json_resume,
            "docx_url": docx_url
        }
    }

# 7) 示例：你可以在 qa/views.py 的接口里调用它
# from rest_framework.views import APIView
# from rest_framework.response import Response
# class QaAPIView(APIView):
#     def post(self, request):
#         question = request.data.get("question")
#         userid = request.data.get("userid")
#         result = generate_resume_pipeline(question, int(userid))
#         return JsonResponse(result)
